package dao

import (
	"errors"
	"go.uber.org/zap"
	"golang.org/x/crypto/bcrypt"
	"gorm.io/gorm"
	"kf/models/entity"
	"kf/utils"
	"strconv"
	"strings"
	"time"
)

type SysUserDao struct {
	DB             *gorm.DB
	SysUserRoleDao *SysUserRolesDao
	Log            *zap.Logger
}

func (sysUserDao *SysUserDao) ListPagedUsers(queryParams entity.SysUserPageQuery) (utils.Page[entity.UserPageVO], error) {
	sql := `SELECT u.id,
				   u.username,
				   u.nickname,
				   u.mobile,
					u.gender,
					u.avatar,
					u.status,
					d.NAME AS dept_name,
           GROUP_CONCAT( r.NAME ) AS role_names,
           u.create_time
       FROM
           sys_user u
               LEFT JOIN sys_dept d ON u.dept_id = d.id
               LEFT JOIN sys_user_role sur ON u.id = sur.user_id
               LEFT JOIN sys_role r ON sur.role_id = r.id
               where
               u.is_deleted = 0 AND u.username != 'root'`

	where := ""
	if queryParams.PageQuery.Keywords != nil && *queryParams.PageQuery.Keywords != "" {
		where = ` and (
		           u.username LIKE '%` + *queryParams.PageQuery.Keywords + `%'
		           OR u.nickname LIKE '%` + *queryParams.PageQuery.Keywords + `%'
		           OR u.mobile LIKE '%` + *queryParams.PageQuery.Keywords + `%'
		           )`
	}
	if queryParams.Status != nil {
		status := `AND u.status = ` + string(*queryParams.Status)
		where = where + status
	}
	if queryParams.DeptId != nil {
		dept := ` AND concat(',',concat(d.tree_path,',',d.id),',') like ` + `'%` +
			strconv.FormatUint(*queryParams.DeptId, 10) + `%'`
		where = where + dept
	}
	if queryParams.StartTime != nil {
		startTime := ` AND u.create_time > ` + (*queryParams.StartTime).Format("2006-01-02")
		where = where + startTime
	}
	if queryParams.EndTime != nil {
		endTime := ` AND u.create_time > ` + (*queryParams.EndTime).Format("2006-01-02")
		where = where + endTime
	}
	if where != "" {
		sql = sql + where + ` GROUP BY u.id`
	} else {
		sql = sql + ` GROUP BY u.id`
	}

	var totalRecords int64
	page := *queryParams.PageQuery.PageNum      // 当前页码
	pageSize := *queryParams.PageQuery.PageSize // 每页数据量

	// 计算偏移量
	offset := (page - 1) * pageSize
	var users = make([]entity.UserBO, 0)

	var res utils.Page[entity.UserPageVO]

	err := sysUserDao.DB.Raw(sql).Offset(int(offset)).Limit(int(pageSize)).Find(&users).Error
	if err != nil {
		return res, err
	}
	// 获取总记录数
	err = sysUserDao.DB.Model(&entity.SysUser{}).Count(&totalRecords).Error
	if err != nil {
		return res, err
	}

	res.Total = totalRecords
	var userVos []entity.UserPageVO
	for _, bo := range users {
		var vo entity.UserPageVO
		vo.ID = bo.ID
		vo.UserName = bo.UserName
		vo.NickName = bo.NickName
		vo.Mobile = bo.Mobile
		gender := ""
		if bo.Gender == 1 {
			gender = "男"
		}
		if bo.Gender == 2 {
			gender = "女"
		}
		vo.GenderLabel = gender
		vo.Avatar = bo.Avatar
		vo.Email = bo.Email
		vo.Status = bo.Status
		vo.DeptName = bo.DeptName
		vo.RoleNames = bo.RoleNames
		if !bo.CreateTime.IsZero() {
			vo.CreateTime = bo.CreateTime.Format("2006-01-02")
		} else {
			vo.CreateTime = ""
		}

		userVos = append(userVos, vo)
	}
	res.List = userVos
	return res, nil
}

func (sysUserDao *SysUserDao) UpdatePassword(userId int, password string) bool {
	// 生成密码的哈希值
	// 第二个参数是成本参数，其值可以是4到31之间的任何整数，默认值是10
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		panic(err)
	}
	sysUser := entity.SysUser{
		Password: string(hashedPassword),
	}
	sysUserDao.DB.Updates(&sysUser).Where("id = ?", userId)
	return true
}

func (sysUserDao *SysUserDao) GetUserForm(id int64) (entity.UserForm, error) {
	var userForm entity.UserForm
	var user entity.SysUser
	err := sysUserDao.DB.
		Table("sys_user").
		Select("id,username,nickname,mobile,gender,avatar,email,status,dept_id").
		Where("id = ? and is_deleted = 0", id).
		Find(&user).Error
	if err != nil {
		sysUserDao.Log.Error("查询用户信息报错", zap.Error(err))
		return userForm, err
	}
	userForm.ID = user.ID
	userForm.UserName = user.UserName
	userForm.NickName = user.NickName
	userForm.Mobile = user.Mobile
	userForm.Gender = user.Gender
	userForm.Avatar = user.Avatar
	userForm.Email = user.Email
	userForm.Status = user.Status
	userForm.DeptId = user.DeptId

	userRoles := sysUserDao.SysUserRoleDao.FindRolesByUserId(userForm.ID)
	var roleIds []uint64
	for _, userRole := range userRoles {
		roleIds = append(roleIds, userRole.RoleId)
	}
	userForm.RoleIds = roleIds
	return userForm, nil
}

// 根据用户id查询
func (sysUserDao *SysUserDao) FindSysUserById(id string) (entity.SysUser, error) {
	var sysUser entity.SysUser
	if id == "" {
		return sysUser, nil
	}
	err := sysUserDao.DB.Model(&entity.SysUser{}).
		Where("id = ?", id).
		First(&sysUser).Error
	if err != nil {
		return sysUser, err
	}
	return sysUser, nil
}

// 根据用户名称查询
func (sysUserDao *SysUserDao) FindSysUserByUserName(username string) (entity.SysUser, error) {
	var sysUser entity.SysUser
	err := sysUserDao.DB.Model(&entity.SysUser{}).Where("username = ?", username).First(&sysUser).Error
	if err != nil {
		return sysUser, err
	}
	return sysUser, nil
}

// 获取所有用户
func (sysUserDao *SysUserDao) FindUsers() ([]entity.SysUser, error) {
	var sysUsers []entity.SysUser
	err := sysUserDao.DB.Model(&entity.SysUser{}).Find(&sysUsers).Error
	if err != nil {
		return sysUsers, err
	}
	return sysUsers, nil
}

func (sysUserDao *SysUserDao) SaveUser(userForm entity.UserForm) (bool, error) {
	err := sysUserDao.DB.Transaction(func(tx *gorm.DB) error {
		username := userForm.UserName
		var count int64
		tx.Model(&entity.SysUser{}).Where("username = ?", username).Count(&count)
		if count > 0 {
			return errors.New("用户名已存在")
		}

		hashedPassword, err := bcrypt.GenerateFromPassword([]byte("123456"), bcrypt.DefaultCost)
		if err != nil {
			sysUserDao.Log.Error("密码设置错误", zap.Error(err))
			return errors.New("密码设置错误")
		}
		var sysUser = entity.SysUser{
			Model: entity.Model{
				CreateTime: time.Now(),
				IsDeleted:  0,
			},
			UserName: userForm.UserName,
			NickName: userForm.NickName,
			Gender:   userForm.Gender,
			Password: string(hashedPassword),
			DeptId:   userForm.DeptId,
			Avatar:   userForm.Avatar,
			Mobile:   userForm.Mobile,
			Status:   userForm.Status,
			Email:    userForm.Email,
		}
		// 新增用户
		err = sysUserDao.DB.Model(&entity.SysUser{}).Save(&sysUser).Error
		if err == nil {
			// 保存用户角色
			sysUserDao.SysUserRoleDao.saveUserRoles(sysUser.ID, userForm.RoleIds)
			return nil
		} else {
			sysUserDao.Log.Error("保存新用户失败", zap.Error(err))
			return errors.New("保存新用户失败")
		}
	})
	if err != nil {
		return false, err
	}
	return true, nil
}

// 修改用户
func (sysUserDao *SysUserDao) UpdateUser(userForm entity.UserForm) (b bool, err error) {
	err = sysUserDao.DB.Transaction(func(tx *gorm.DB) error {
		username := userForm.UserName
		var count int64
		tx.Model(&entity.SysUser{}).Where("username = ? and id <> ?", username, userForm.ID).Count(&count)
		if count > 0 {
			b = false
			err = errors.New("用户名已存在")
			return err
		}

		var sysUser = entity.SysUser{
			Model: entity.Model{
				ID:         userForm.ID,
				UpdateTime: time.Now(),
				IsDeleted:  0,
			},
			UserName: userForm.UserName,
			NickName: userForm.NickName,
			Gender:   userForm.Gender,
			DeptId:   userForm.DeptId,
			Avatar:   userForm.Avatar,
			Mobile:   userForm.Mobile,
			Status:   userForm.Status,
			Email:    userForm.Email,
		}
		// 新增用户
		err = sysUserDao.DB.Model(&entity.SysUser{}).Where("id = ? ", sysUser.ID).Updates(&sysUser).Error
		if err == nil {
			// 保存用户角色
			sysUserDao.SysUserRoleDao.saveUserRoles(sysUser.ID, userForm.RoleIds)
			b = true
			err = nil
			return nil
		} else {
			b = false
			err = errors.New("修改用户失败")
			return err
		}
	})
	if err != nil {
		return false, err
	}
	return true, nil
}

func (sysUserDao *SysUserDao) DeleteUsers(ids string) (bool, error) {
	if ids == "" {
		return false, errors.New("至少需要一个参数")
	}
	split := strings.Split(ids, ",")

	err := sysUserDao.DB.Transaction(func(tx *gorm.DB) error {
		var list []uint64
		for _, val := range split {
			end, _ := strconv.ParseUint(val, 10, 64)
			list = append(list, end)
		}
		err := sysUserDao.DB.Delete(&entity.SysUser{}, list).Error
		return err
	})
	if err != nil {
		return false, err
	} else {
		return true, nil
	}
}

func (sysUserDao *SysUserDao) Option() ([]entity.UserOption, error) {
	var options []entity.UserOption
	err := sysUserDao.DB.Model(&entity.SysUser{}).Select("id,username").
		Find(&options).Error
	if err != nil {
		return options, err
	}
	return options, nil
}

// 随机获取一个客服
func (sysUserDao *SysUserDao) FindSysUserRandom() (entity.SysUser, error) {
	var user entity.SysUser
	sysUserDao.DB.Model(&entity.SysUser{}).Raw("SELECT * FROM sys_user ORDER BY RAND() LIMIT 1").Find(&user)
	return user, nil
}
